package summarizer.newversion;

import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;

import thesis.FSModule;
import thesis.InfoUnit;
import thesis.DataObject;
import thesis.Summary;
import thesis.DataUtil;

import com.aliasi.util.Pair;

public class GreedySummarizerTweetOptNewFilter extends Summarizer {

	private final double alpha;
	private final double beta;
	private final double gamma;
	private final double[][] probs;
	private final ArrayList<InfoUnit> infoUnits;
	private HashMap<Long, DataObject> memoryTweets = new HashMap<Long, DataObject>();
	private double totalInfo;

	public GreedySummarizerTweetOptNewFilter(final double[][] probs,
			ArrayList<InfoUnit> infoUnits, double alpha, double beta,
			double gamma) {
		this.alpha = alpha;
		this.beta = beta;
		this.gamma = gamma;
		this.infoUnits = infoUnits;
		this.probs = probs;
	}

	private double getTotalC(HashMap<Long, DataObject> tweets) {
		double total = 0;
		for (DataObject t : tweets.values()) {
			for (Pair<Double, InfoUnit> pair : t.getUnits()) {
				total += pair.a() * pair.b().getWeight();
			}
		}
		return total;
	}

	private DataObject preprocess(Summary summary, int summaryDimension,
			int dimSize) {
		// initialized totalInfo contained in each tweet
		this.totalInfo = this.getTotalC(memoryTweets);
		for (DataObject t : this.memoryTweets.values()) {
			t.setQual(t.getQuality() / summaryDimension);
			//t.setDiv(1);
		}
		// set gain for each unit
		for (InfoUnit unit : this.infoUnits) {
			unit.setGain(0);
		}
		for (DataObject t : this.memoryTweets.values()) {
			for (Pair<Double, InfoUnit> pair : t.getUnits()) {
				InfoUnit unit = pair.b();
				unit.setGain(unit.getGain() + unit.getWeight() * pair.a());
			}
		}
		for (DataObject t : this.memoryTweets.values()) {
			double cov = 0;
			for (Pair<Double, InfoUnit> pair : t.getUnits()) {
				InfoUnit unit = pair.b();
				double covProb = probs[t.getInternId()][unit.getInternId()];
				double gainT = covProb * unit.getWeight();
				cov += gainT + covProb * (unit.getGain() - gainT);
			}
			t.setOrigCov(cov / this.totalInfo);
			t.setCov(t.getOrigCov());
		}
		// find tweet with best quality
		DataObject bestT = null;
		double bestScore = -1;
		for (DataObject t : memoryTweets.values()) {
			double score = alpha * t.getQual() + gamma * t.getOrigCov();
			if (score > bestScore) {
				bestScore = score;
				bestT = t;
			}
		}
		summary.addMemoryTweet(bestT);
		this.memoryTweets.remove(bestT.getDbId());
		for (InfoUnit unit : this.infoUnits) {
			unit.setCovProb(probs[bestT.getInternId()][unit.getInternId()]);
			unit.setGain(unit.getGain()
					- probs[bestT.getInternId()][unit.getInternId()]
					* unit.getWeight());
		}
		return bestT;
	}

	private void greedProcess(int summaryDimension, int numberOfPages,
			Summary summary, DataObject bestT) {
		while (summary.size() < summaryDimension) {
			DataObject prevT = bestT;
			for (DataObject t : this.memoryTweets.values()) {
				t.setQual(t.getQual() + bestT.getQuality() / summaryDimension);
//				t.setDiv(Math.min(DataUtil.dist(t, bestT),
//						Math.min(t.getDiv(), bestT.getDiv())));
				double cov = 0;
				for (Pair<Double, InfoUnit> pair : t.getUnits()) {
					InfoUnit unit = pair.b();
					double covProb = probs[t.getInternId()][unit.getInternId()];
					double gainT = covProb * unit.getWeight();
					cov += probs[t.getInternId()][unit.getInternId()]
							* (1 - unit.getCovProb())
							* (unit.getWeight() + unit.getGain() - gainT);
				}
				t.setCov(bestT.getCov() + cov / this.totalInfo);
			}
			double bestScore = -1;
			for (DataObject t : this.memoryTweets.values()) {
				double score = alpha * t.getQual() + beta * t.getDiv() + gamma
						* t.getCov();
				if (score > bestScore) {
					bestScore = score;
					bestT = t;
				}
			}
			summary.addMemoryTweet(bestT);
			this.memoryTweets.remove(bestT.getDbId());
			// compute coverage of each information unit by current summary
			for (Pair<Double, InfoUnit> pair : bestT.getUnits()) {
				InfoUnit info = pair.b();
				info.setCovProb(1 - (1 - info.getCovProb())
						* (1 - probs[bestT.getInternId()][info.getInternId()]));
				double gainBest = probs[bestT.getInternId()][info.getInternId()]
						* info.getWeight();
				info.setGain(info.getGain() - gainBest);
			}
//			if (FSModule.DEBUG) {
//				System.out.println("Summary size: " + summary.size());
//				System.out.println("Quality: " + bestT.getQual()
//						+ " Diversity: " + bestT.getDiv() + " Coverage: "
//						+ bestT.getCov());
//			}

		}
	}

	public Summary computeSummary(int summaryDimension, int numberOfPages,
			HashMap<Long, DataObject> tweets, int dimSize) {
		this.memoryTweets = tweets;
		Summary summary = new Summary();
		if (summaryDimension <= 0 || this.memoryTweets.isEmpty()) {
			return summary;
		}
		executionTime = (new GregorianCalendar()).getTimeInMillis();
		DataObject bestT = preprocess(summary, summaryDimension, dimSize);
		greedProcess(summaryDimension, numberOfPages, summary, bestT);
		executionTime = (new GregorianCalendar()).getTimeInMillis()
				- executionTime;
		return summary;
	}

	public String toString() {
		return "Greedy Summarizer Tweet Level Opt New Filter" + "<" + alpha
				+ " " + beta + " " + gamma + ">";
	}

	public long getExecutionTime() {
		return executionTime;
	}
}
